/*******************************************************************
 *                                                                 *
 *  mcouda.h                                                    *
 *                                                                 *
 *  This file is a part of the eXtremeDB source code               *
 *  Copyright (c) 2001-2012 McObject LLC                           * 
 *  All Rights Reserved                                            *
 *                                                                 *
 *  eXtremeDB runtime uniform data access API                      * 
 *                                                                 *
 *******************************************************************/
#ifndef MCO_UNIFORM_DATA_ACCESS_API_H
#define MCO_UNIFORM_DATA_ACCESS_API_H

#ifdef __cplusplus
    extern "C"
    {
#endif 


#include <mco.h>
#ifdef MCO_CFG_WCHAR_SUPPORT
    #include <stdarg.h>
    #ifndef _VXWORKS
        #include <ctype.h>
        #include <wctype.h>
        #ifndef _WIN32
	   #if defined(_QNX) && defined(__cplusplus)
		#undef __cplusplus
		#include <wchar.h>
		#define __cplusplus
	   #else
		#include <wchar.h>
	   #endif
        #endif
    #else 
        #include <stdlib.h>
    #endif 
#endif

/* Dictionary access API */
typedef struct tag_mco_metadict_entry_t_ {
    unsigned short dict_no;
    unsigned short flags;
    char           name[16]; /* MCO_CFG_DB_NAME_MAXSIZE in mcocfg.h */
    void         * dict;
    void         * user_data;
} mco_metadict_entry_t;

typedef struct tag_mco_metadict_header_t_ {
    unsigned short n_maxentries;
    unsigned short n_allocated;
    mco_metadict_entry_t entries[1];
} mco_metadict_header_t;

/* Get size of memory region enought to fit requires number of entries.
 * In case of statical memory allocation please ensure in properly memory alignment:
 * 
 * char array[(sizeof(mco_metadict_header_t)+sizeof(mco_metadict_entry_t)*n_entries+3) & ~(3)];
 */
void         mco_metadict_size       ( unsigned short n_entries, /* out */ unsigned int * size );

/* Initialize the metadict and load initial state from eXdb registry */
#define MCO_METADICT_DONT_LOAD_EXISTING_DBS 	1
MCO_RET      mco_metadict_init       ( mco_metadict_header_t * metadict, unsigned int size, unsigned int flags );

/* Put a dict. into the metadict. */
MCO_RET      mco_metadict_register   ( mco_metadict_header_t * metadict, const char * name, const void * dict, const void * user_data );

/* Get number of records in the metadict. */
MCO_RET      mco_metadict_count      ( const mco_metadict_header_t * metadict, 
                                                                  /* out */ unsigned short * count );

/* Get a record from the metadict. by index */
MCO_RET      mco_metadict_entry      ( const mco_metadict_header_t * metadict, unsigned short dict_no, 
                                                                  /* out */ mco_metadict_entry_t ** entry );
/* Get a record from the metadict. by name */
MCO_RET      mco_metadict_entry_name ( const mco_metadict_header_t * metadict, const char * name,
                                                                  /* out */ mco_metadict_entry_t ** entry );

/* Get a record from the metadict. by connection */
MCO_RET      mco_metadict_entry_conn ( const mco_metadict_header_t * metadict, const mco_db_h connection,
                                                                  /* out */ mco_metadict_entry_t ** entry );
typedef enum tag_mco_dict_type_t_ {
    MCO_DD_UINT1,
    MCO_DD_UINT2,
    MCO_DD_UINT4,
    MCO_DD_UINT8,
    MCO_DD_INT1,
    MCO_DD_INT2,
    MCO_DD_INT4,
    MCO_DD_INT8,
    MCO_DD_FLOAT,
    MCO_DD_DOUBLE,
    MCO_DD_DATE,
    MCO_DD_TIME,
    MCO_DD_CHAR,
    MCO_DD_NCHAR_CHAR,
    MCO_DD_WIDE_CHAR,
    MCO_DD_STRING,
    MCO_DD_NCHAR_STRING,
    MCO_DD_WCHAR_STRING,
    MCO_DD_REF,
    MCO_DD_AUTOID,
    MCO_DD_AUTOOID,
    MCO_DD_STRUCT,
    MCO_DD_BLOB,
    MCO_DD_OID,
    MCO_DD_BOOL
} mco_dict_type_t;

#define MCO_DICT_SI_CLASS                 0x1
#define MCO_DICT_SI_OID                   0x2
#define MCO_DICT_SI_AUTOID                0x4
#define MCO_DICT_SI_LIST                  0x8
#define MCO_DICT_SI_PERSISTENT           0x10
#define MCO_DICT_SI_EVENT_NEW            0x20
#define MCO_DICT_SI_EVENT_DEL            0x40
#define MCO_DICT_SI_EVENT_UPD            0x80
#define MCO_DICT_SI_EVENT_DELALL        0x100
#define MCO_DICT_SI_EVENT_CHECKPOINT    0x200
#define MCO_DICT_SI_EVENT_CLASS_UPDATE  0x400
#define MCO_DICT_SI_COMPACT             0x800
#define MCO_DICT_SI_PACKED              0x1000
#define MCO_DICT_SI_DIRECT              0x2000

typedef struct tag_mco_dict_struct_info_t_ {
    unsigned short  struct_no;
    char          * name;
    unsigned int    flags;
    unsigned short  index_count;
    unsigned short  field_count;
    unsigned short  event_count;
    unsigned short  class_code;
    unsigned short  new_event_no;
    unsigned short  delete_event_no;
    unsigned short  delete_all_event_no;
    unsigned short  checkpoint_event_no;
    unsigned short  class_update_event_no;

} mco_dict_struct_info_t, * mco_dict_struct_info_p;

/* Number of classes and structs in the dict. */
MCO_RET mco_dict_struct_count( const mco_metadict_header_t * metadict, unsigned short dict_no, 
                                                        /* out */ unsigned short * count );
MCO_RET mco_dict_struct      ( const mco_metadict_header_t * metadict, unsigned short dict_no, 
                               unsigned short struct_no, 
                                                        /* out */ mco_dict_struct_info_p struct_info );
MCO_RET mco_dict_struct_name ( const mco_metadict_header_t * metadict, unsigned short dict_no, 
                               const char * name, 
                                                        /* out */ mco_dict_struct_info_p struct_info );

#define MCO_DICT_FI_OPTIONAL             0x1
#define MCO_DICT_FI_INDEXED              0x2
#define MCO_DICT_FI_VECTOR               0x4
#define MCO_DICT_FI_ARRAY                0x8
#define MCO_DICT_FI_EVENT_UPD		0x10
#define MCO_DICT_FI_HAS_INIT_DATA	0x20
#define MCO_DICT_FI_NULLABLE            0x40  /* field is nullable  */
#define MCO_DICT_FI_NULL_INDICATOR      0x80  /* field is null indicator */

typedef struct tag_mco_dict_field_info_t_ {
    unsigned short     field_no;
    char             * name;
    mco_dict_type_t    type;       
    unsigned int       flags;
    unsigned short     dimension;
    unsigned short     struct_no; /* used if field is nested struct/optional struct */
    unsigned short     update_event_no;
    unsigned int       size;
} mco_dict_field_info_t, * mco_dict_field_info_p;

MCO_RET mco_dict_field       ( const mco_metadict_header_t * metadict, unsigned short dict_no,
                               unsigned short struct_no, unsigned short field_no,
                                                        /* out */ mco_dict_field_info_p field_info );
MCO_RET mco_dict_field_name  ( const mco_metadict_header_t * metadict, unsigned short dict_no, 
                               unsigned short struct_no, const char * name, 
                                                        /* out */ mco_dict_field_info_p field_info );

#define MCO_DICT_II_UNIQUE     1
#define MCO_DICT_II_VOLUNTARY  2
#define MCO_DICT_II_LIST       4
#define MCO_DICT_II_AUTOID     8
#define MCO_DICT_II_TREE       0x10
#define MCO_DICT_II_HASH       0x20
#define MCO_DICT_II_USERDEF    0x40
#define MCO_DICT_II_KDTREE     0x80
#define MCO_DICT_II_RTREE      0x100
#define MCO_DICT_II_PATRICIA   0x200
#define MCO_DICT_II_NULLABLE   0x400

typedef struct tag_mco_dict_index_info_t_ {
    unsigned short     index_no;
    char             * name;
    unsigned int       flags;
    unsigned short     n_fields;
    unsigned short     index; /* continuous index numbering in terms of function mco_index_stat_get */
    unsigned int       n_keys_estimate;
} mco_dict_index_info_t, * mco_dict_index_info_p;

MCO_RET mco_dict_index       ( const mco_metadict_header_t * metadict, unsigned short dict_no,
                               unsigned short struct_no, unsigned short index_no,
                                                        /* out */ mco_dict_index_info_p index_info );
MCO_RET mco_dict_index_name  ( const mco_metadict_header_t * metadict, unsigned short dict_no, 
                               unsigned short struct_no, const char * name, 
                                                        /* out */ mco_dict_index_info_p index_info );

#define MCO_DICT_IFI_DESCENDING 1 
#define MCO_DICT_IFI_NULLABLE   2
typedef struct tag_mco_dict_ifield_info_t_ {
    unsigned short     ifield_no;
    unsigned short     field_no; /* name, type */
    unsigned int       flags;
    short              coll_no;
} mco_dict_ifield_info_t, * mco_dict_ifield_info_p;

MCO_RET mco_dict_ifield      ( const mco_metadict_header_t * metadict, unsigned short dict_no,
                               unsigned short struct_no, unsigned short index_no, unsigned short ifield_no,
                                                        /* out */ mco_dict_ifield_info_p ifield_info );
MCO_RET mco_dict_ifield_name ( const mco_metadict_header_t * metadict, unsigned short dict_no, 
                               unsigned short struct_no, unsigned short index_no, const char * name, 
                                                        /* out */ mco_dict_ifield_info_p ifield_info );

typedef struct tag_mco_dict_nested_ifield_info_t_ {
    unsigned short     ifield_no;
    unsigned short     level;
    unsigned short     struct_no;
    unsigned short     field_no;
    unsigned int       flags;
    short              coll_no;
} mco_dict_nested_ifield_info_t, * mco_dict_nested_ifield_info_p;

MCO_RET mco_dict_nested_ifield ( const mco_metadict_header_t * metadict, unsigned short dict_no,
                               unsigned short struct_no, unsigned short index_no, unsigned short ifield_no,
                               unsigned short level, /* out */ mco_dict_nested_ifield_info_p nested_ifield_info );

typedef struct tag_mco_dict_collation_info_t_ {
    unsigned short  collation_no;
    mco_dict_type_t type;
    char          * name;
} mco_dict_collation_info_t, * mco_dict_collation_info_p;

MCO_RET mco_dict_collation_count( const mco_metadict_header_t * metadict, unsigned short dict_no, 
                                                        /* out */ unsigned short * count );
MCO_RET mco_dict_collation      ( const mco_metadict_header_t * metadict, unsigned short dict_no,
                                  unsigned short collation_no, /* out */ mco_dict_collation_info_p coll_info );
MCO_RET mco_dict_collation_name ( const mco_metadict_header_t * metadict, unsigned short dict_no, 
                                  const char * name, /* out */ mco_dict_collation_info_p coll_info );


typedef struct tag_mco_dict_event_info_t_ {
    unsigned short  event_no;
    MCO_EVENT_TYPE  type;
    unsigned short  field_no; /* for update events only */
} mco_dict_event_info_t, * mco_dict_event_info_p;

MCO_RET mco_dict_event ( const mco_metadict_header_t *metadict, unsigned short dict_no, 
                         unsigned short struct_no, unsigned short event_no, 
                            /* out */ mco_dict_event_info_p event_info);    

/* Data access API */

typedef struct tag_mco_uda_object_handle_t_ {
    MCO_Hf obj;
    unsigned short struct_no;
} mco_uda_object_handle_t, * mco_uda_object_handle_p;

typedef struct tag_mco_uda_value_t_ {

    mco_dict_type_t type;
    union {
        unsigned char           u1;   /* MCO_DD_UINT1 */
        unsigned short          u2;   /* MCO_DD_UINT2 */
        unsigned int            u4;   /* MCO_DD_UINT4, MCO_DD_DATE, MCO_DD_TIME */
        uint8                   u8;   /* MCO_DD_UINT8, MCO_DD_AUTOID, MCO_DD_AUTOOID */
        char                    i1;   /* MCO_DD_INT1 */
        short                   i2;   /* MCO_DD_INT2 */
        int                     i4;   /* MCO_DD_INT4 */
        int8                    i8;   /* MCO_DD_INT8 */
        #ifdef MCO_TARGET_FLOAT_SUPPORTED        
            float               f;    /* MCO_DD_FLOAT */
            double              d;    /* MCO_DD_DOUBLE */
        #endif
        mco_uda_object_handle_t o;    /* MCO_DD_STRUCT */
        struct {
            unsigned short      size; /* size of a buffer in bytes */
            unsigned short      len;  /* length of a string in characters */ 
            union {
                char          * c;    /* char strings: MCO_DD_STRING, MCO_DD_CHAR */
                nchar_t       * n;    /* nchar strings: MCO_DD_NCHAR_STRING, MCO_DD_NCHAR_CHAR */
                #ifdef MCO_CFG_WCHAR_SUPPORT 
                    wchar_t   * w;    /* wchar strings: MCO_DD_WCHAR_STRING, MCO_DD_WIDE_CHAR */
                #endif 
                void          * v;    /* general pointer : MCO_DD_BLOB, MCO_DD_REF, MCO_DD_OID */
            } p;                      /* pointer to the buffer */
        } p;                          
    } v;
} mco_uda_value_t, * mco_uda_value_p;

/* Create new object. */
MCO_RET mco_uda_new         ( mco_trans_h t, unsigned short struct_no, 
                              const void * oid, 
                              const mco_uda_value_t * initializers, unsigned short initializers_no,
                                                        /* out */ mco_uda_object_handle_t * obj );

MCO_RET mco_uda_delete      ( mco_uda_object_handle_t * obj );

/* Delete all objects of the given type */
MCO_RET mco_uda_delete_all  ( mco_trans_h t, unsigned short stuct_no);

MCO_RET mco_uda_checkpoint  ( mco_uda_object_handle_t * obj );

/* Get object class code */
MCO_RET mco_uda_get_class_code( mco_uda_object_handle_t *obj, unsigned short *class_code);

/* Makes MCO_Hf by mco_uda_object_handle_t */
MCO_RET mco_uda_to_mco(mco_uda_object_handle_t *udaobj, /* OUT */ MCO_Hf *ret);

/* Makes mco_uda_object_handle_t by MCO_Hf */
MCO_RET mco_uda_from_mco(MCO_Hf *mcoobj, /* OUT */ mco_uda_object_handle_t *ret);


/* Open a cursor for object enumeration */
MCO_RET mco_uda_cursor      ( mco_trans_h t, unsigned short struct_no, unsigned short index_no,
                                                        /* out */ mco_cursor_t * cursor );

MCO_RET mco_uda_lookup      ( mco_trans_h t, unsigned short struct_no, unsigned short index_no, 
                              MCO_OPCODE op, const mco_uda_value_t * keys, unsigned short keys_count,
                                                        /* out */ mco_cursor_t * cursor );

MCO_RET mco_uda_from_cursor ( mco_trans_h t, const mco_cursor_t * cursor,
                                                        /* out */ mco_uda_object_handle_t * obj );

/* request cursor bindings */
MCO_RET mco_uda_cursor_info ( mco_trans_h t, const mco_metadict_header_t * metadict, const mco_cursor_t * cursor,
                                                        /* out */ unsigned short * dict_no,
                                                        /* out */ unsigned short * struct_no,
                                                        /* out */ unsigned short * index_no ); 

MCO_RET mco_uda_locate      ( mco_trans_h t, const mco_uda_object_handle_p obj, unsigned short index_no,
                                                        /* out */ mco_cursor_t * cursor );

MCO_RET mco_uda_compare     ( mco_trans_h t, const mco_cursor_t * cursor, 
                              const mco_uda_value_t * keys, unsigned short keys_count,
                                                        /* out */ int * cmp_result );

/* pattern search */
MCO_RET  mco_uda_pattern_size(const mco_metadict_header_t *metadict, unsigned short dict_no, unsigned short struct_no, unsigned short index_no,  
                const mco_uda_value_t * keys, unsigned short keys_count, /* out */ uint4 *memsize);

MCO_RET  mco_uda_pattern_search( mco_trans_h t, unsigned short struct_no, unsigned short index_no, const mco_uda_value_t * keys, 
                unsigned short keys_count, /* inout */ mco_cursor_h cursor, /* inout */ void *allocated_pattern);

MCO_RET  mco_uda_pattern_next(mco_trans_h t, mco_cursor_h cursor, /* inout */ void *allocated_pattern);


/* Get current length of an array or a vector */
MCO_RET mco_uda_length      ( const mco_uda_object_handle_p obj, unsigned short field_no, 
                                                        /* out */ unsigned short * dimension );

/* Get value of a scalar field, element of a vector or array, blob or struct.
 * 
 * Application should specify mco_dd_value_t.type field only for any datatypes but strings and blobs.
 * In case of a structured field mco_dd_value_t.o used.
 * The application should use following technique to get value of  string or blob fields:
 * 1. Put datatype code in type field
 * 2. Put zero in mco_dd_value_t.p.p.* field
 * 3. Call mco_dd_get() first time to get size of value (mco_dd_value_t.p.size).
 * 4. Put a pointer to allocated memory region into one of mco_dd_value_t.p.p.*
 * 5. Call mco_dd_get() one more time to get the value into spec. buffer.
 *
 * If the buffer is not enought to contain full value of a string or blob field then only part 
 * of the value will be returned. 
 * If the buffer is larger then the value then mco_dd_get() will put a zero-terminator in the end of the
 * string value.
 */
MCO_RET mco_uda_get         ( const mco_uda_object_handle_p obj, unsigned short field_no, unsigned short index,  
                                                        /* out */ mco_uda_value_t * buf );

MCO_RET mco_uda_put         ( mco_uda_object_handle_p obj, unsigned short field_no, unsigned short index, 
                             const mco_uda_value_p value );

/* Get default value for the field, eihter scalar or array element
 * strings are not supported here 
 */
MCO_RET mco_dict_field_init_data(const mco_metadict_header_t * metadict, unsigned short dict_no,
                       unsigned short struct_no, unsigned short field_no, unsigned short index,
                                        /* out */ mco_uda_value_t * buf);

/* vectors and optional structs ops */

/* allocate a vector or optional struct field */
MCO_RET mco_uda_field_alloc ( mco_uda_object_handle_p obj, unsigned short field_no, unsigned short length );

/* free a vector element or optional struct field */
MCO_RET mco_uda_field_free  ( mco_uda_object_handle_p obj, unsigned short field_no, unsigned short index );

/* Find object by OID */
MCO_RET mco_uda_oid_find( mco_trans_h t, const mco_uda_value_t *id, /* out */ mco_uda_object_handle_p obj);


/* userdef indices support */

typedef int2 (*mco_uda_compare_userdef_f)(mco_uda_object_handle_p obj1, unsigned short index1, 
                                        mco_uda_object_handle_p obj2, unsigned short index2, void *user_context);
typedef int2 (*mco_uda_compare_extkey_userdef_f)(mco_uda_object_handle_p obj, unsigned short index, 
                                        mco_uda_value_t *keys, uint2 keys_count, void *user_context);
typedef uint4 (*mco_uda_hash_userdef_f)(mco_uda_object_handle_p obj, unsigned short index, void *user_context);
typedef uint4 (*mco_uda_hash_extkey_userdef_f)(mco_uda_value_t *keys, uint2 keys_count, void *user_context);

typedef struct mco_uda_userdef_funcs_t_ {
    mco_uda_compare_userdef_f         fcomp;
    mco_uda_compare_extkey_userdef_f  fcomp_ext;
    mco_uda_hash_userdef_f            fhash;
    mco_uda_hash_extkey_userdef_f     fhash_ext;
} mco_uda_userdef_funcs_t, *mco_uda_userdef_funcs_h;

MCO_RET mco_uda_get_udfmap_size(const mco_metadict_header_t * metadict, unsigned short dict_no, /* out */ unsigned int * size);

MCO_RET mco_uda_register_udf(const mco_metadict_header_t * metadict, unsigned short dict_no, 
                                        unsigned short struct_no, unsigned short index_no, mco_userdef_funcs_h udf_map, 
                                        mco_uda_userdef_funcs_h udf_entry, void *user_context);

MCO_RET mco_uda_get_collmap_size(const mco_metadict_header_t * metadict, unsigned short dict_no, /* out */ unsigned int * size);
MCO_RET mco_uda_register_collation(const mco_metadict_header_t * metadict, unsigned short dict_no, 
                                unsigned short collation_no, mco_collation_funcs_h coll_map, 
                                mco_compare_collation_f fcomp, mco_hash_collation_f fhash);

MCO_RET mco_uda_collate_get(mco_collate_h c, /* out */ mco_uda_value_t * val);
MCO_RET mco_uda_collate_get_range(mco_collate_h c, uint2 from, /* out */ mco_uda_value_t * val);


#define MCO_UDA_CLASS_DEFAULT    0
#define MCO_UDA_CLASS_TRANSIENT  1
#define MCO_UDA_CLASS_PERSISTENT 2

typedef struct {
    uint2 class_code;
    uint1 persistence;
} mco_uda_dict_class_storage_t;

MCO_RET mco_uda_db_open(const mco_metadict_header_t * metadict, unsigned short dict_no, 
                            mco_device_t * devs, mco_size_t n_devs, mco_db_params_t * params,
                            mco_uda_dict_class_storage_t *dict_classes_storage, uint2 n_dict_classes_storage);


MCO_RET mco_uda_db_close(const mco_metadict_header_t * metadict, unsigned short dict_no);

/* Events support */
/* Synchronous events */
typedef MCO_RET (*mco_uda_event_handler)( mco_trans_h t, mco_uda_object_handle_p obj, const mco_dict_event_info_t *event_info, /* inout */ void *param );

MCO_RET mco_uda_register_event_handler( mco_trans_h t, unsigned short struct_no, unsigned short event_no,
                                        mco_uda_event_handler handler, void * param, MCO_HANDLING_ORDER when);

MCO_RET mco_uda_unregister_event_handler( mco_trans_h t, unsigned short struct_no, unsigned short event_no,
                                        mco_uda_event_handler handler);

MCO_RET  mco_uda_updated_bitmap_get_fld(mco_uda_object_handle_t *handle, uint2* index, unsigned short *field_no);

/* Asynchronous events */
MCO_RET mco_uda_async_event_wait(mco_db_h dbh, unsigned short struct_no, unsigned short event_no);
MCO_RET mco_uda_async_event_release(mco_db_h dbh, unsigned short struct_no, unsigned short event_no);
MCO_RET mco_uda_async_event_release_all(mco_db_h dbh);

#ifdef __cplusplus
    }
#endif 

#endif /* MCO_UNIFORM_DATA_ACCESS_API_H */

